import logging

from functools import wraps


logger = logging.getLogger(__name__)


class FailoverException(Exception):
    """
    Exception raised when an operation should be retried by the failover decorator.

    Wraps the exception of the initial failure.
    """

    def __init__(self, exception):
        super(FailoverException, self).__init__()
        self.exception = exception


def failover(func):
    """ Wraps a function such that it can be retried on specified failures.
      Raises FailoverException when all failovers are exhausted.
      Example:

      @failover
      def get_google(scheme, use_www=False):
        www = 'www.' if use_www else ''
        try:
          r = requests.get(scheme + '://' + www + 'google.com')
        except requests.RequestException as ex:
          raise FailoverException(ex)
        return r

      def GooglePingTest():
        r = get_google(
          (('http'), {'use_www': False}),
          (('http'), {'use_www': True}),
          (('https'), {'use_www': False}),
          (('https'), {'use_www': True}),
        )
        print('Successfully contacted ' + r.url)
  """

    @wraps(func)
    def wrapper(*args_sets):
        for arg_set in args_sets:
            try:
                return func(*arg_set[0], **arg_set[1])
            except FailoverException as ex:
                logger.debug("failing over")
                exception = ex.exception
                continue
        raise exception

    return wrapper
